//
//  MessageBean.swift
//  test-ios
//
//  Created by wyz5204 on 2023/7/10.
//

import DifferenceKit
import GRDB

// MARK: - SessionBean
class SessionBean: Codable {
    let unreadNum: Int
    let chatSessions: [ChatSession]
    
    enum CodingKeys: String, CodingKey {
        case unreadNum
        case chatSessions
    }
    
    init(unreadNum: Int, chatSessions: [ChatSession]) {
        self.unreadNum = unreadNum
        self.chatSessions = chatSessions
    }
}

// MARK: SessionBean convenience initializers and mutators

extension SessionBean {
    
    convenience init(data: Data) throws {
        let me = try newJSONDecoder().decode(SessionBean.self, from: data)
        self.init(unreadNum: me.unreadNum, chatSessions: me.chatSessions)
    }
    
    convenience init(_ json: String, using encoding: String.Encoding = .utf8) throws {
        guard let data = json.data(using: encoding) else {
            throw NSError(domain: "JSONDecoding", code: 0, userInfo: nil)
        }
        try self.init(data: data)
    }
    
    convenience init(fromURL url: URL) throws {
        try self.init(data: try Data(contentsOf: url))
    }
    
    func with(
        unreadNum: Int? = nil,
        chatSessions: [ChatSession]? = nil
    ) -> SessionBean {
        return SessionBean(
            unreadNum: unreadNum ?? self.unreadNum,
            chatSessions: chatSessions ?? self.chatSessions
        )
    }
    
    func jsonData() throws -> Data {
        return try newJSONEncoder().encode(self)
    }
    
    func jsonString(encoding: String.Encoding = .utf8) throws -> String? {
        return String(data: try self.jsonData(), encoding: encoding)
    }
}

// MARK: - ChatSession
class ChatSession: Codable{
    var _id : Int64 = -1
    let id, sessionID: String
    let type: Int
    let groupType: Int?
    let labelText: LabelText?
    let image: String?
    let name: String
    let top: Bool
    let notice, from, to: String
    var unreadNum: Int
    let lastModifyTime, updateTime: Int
    let lastMessageText: String
    let disturb: Int
    let delFlag, show: Bool
    let lastMessageSeqID, lastMsgIncrement: String?
    let isReadLastMessage: Int
    let orgID, projectID: Int?
    let reportFlag: String
    let groupNote: String?
    let count, sessionIDStr, singleTo, groupTo: JSONNull?
    let projectGroupPathStr, userIdentity, isOnline, categoryID: JSONNull?
    let categoryPhone: JSONNull?
    let groupNameNote: String
    
    enum CodingKeys: String, CodingKey {
        case id
        case sessionID = "sessionId"
        case type, groupType, labelText, image, name, top, notice, from, to, unreadNum, lastModifyTime, updateTime, lastMessageText, disturb, delFlag, show
        case lastMessageSeqID = "lastMessageSeqId"
        case lastMsgIncrement, isReadLastMessage
        case orgID = "orgId"
        case projectID = "projectId"
        case reportFlag, groupNote, count
        case sessionIDStr = "sessionIdStr"
        case singleTo, groupTo, projectGroupPathStr, userIdentity, isOnline
        case categoryID = "categoryId"
        case categoryPhone, groupNameNote
    }
    
    required init(row: Row) {
        _id                 = row["_id"]
        id                  = row["id"]
        sessionID           = row["sessionId"]
        type                = row["type"]
        image               = row["image"]
        name                = row["name"]
        top                 = row["top"]
        from                = row["from"]
        to                  = row["to"]
        unreadNum           = row["unreadNum"]
        lastModifyTime      = row["lastModifyTime"]
        updateTime          = row["updateTime"]
        lastMessageText     = row["lastMessageText"]
        delFlag             = row["delFlag"]
        show                = row["show"]
        lastMessageSeqID    = row["lastMessageSeqId"]
        lastMsgIncrement    = row["lastMsgIncrement"]
        isReadLastMessage   = row["isReadLastMessage"]
        reportFlag          = row["reportFlag"]
        
        groupType           = nil
        labelText           = nil
        notice              = ""
        disturb             = 0
        orgID               = nil
        projectID           = nil
        groupNote           = ""
        count               = nil
        sessionIDStr        = nil
        singleTo            = nil
        groupTo             = nil
        projectGroupPathStr = nil
        userIdentity        = nil
        isOnline            = nil
        categoryID          = nil
        categoryPhone       = nil
        groupNameNote       = ""
    }
    
    init(id: String, sessionID: String, type: Int, groupType: Int?, labelText: LabelText?, image: String?, name: String, top: Bool, notice: String, from: String, to: String, unreadNum: Int, lastModifyTime: Int, updateTime: Int, lastMessageText: String, disturb: Int, delFlag: Bool, show: Bool, lastMessageSeqID: String?, lastMsgIncrement: String?, isReadLastMessage: Int, orgID: Int?, projectID: Int?, reportFlag: String, groupNote: String?, count: JSONNull?, sessionIDStr: JSONNull?, singleTo: JSONNull?, groupTo: JSONNull?, projectGroupPathStr: JSONNull?, userIdentity: JSONNull?, isOnline: JSONNull?, categoryID: JSONNull?, categoryPhone: JSONNull?, groupNameNote: String) {
        self.id = id
        self.sessionID = sessionID
        self.type = type
        self.groupType = groupType
        self.labelText = labelText
        self.image = image
        self.name = name
        self.top = top
        self.notice = notice
        self.from = from
        self.to = to
        self.unreadNum = unreadNum
        self.lastModifyTime = lastModifyTime
        self.updateTime = updateTime
        self.lastMessageText = lastMessageText
        self.disturb = disturb
        self.delFlag = delFlag
        self.show = show
        self.lastMessageSeqID = lastMessageSeqID
        self.lastMsgIncrement = lastMsgIncrement
        self.isReadLastMessage = isReadLastMessage
        self.orgID = orgID
        self.projectID = projectID
        self.reportFlag = reportFlag
        self.groupNote = groupNote
        self.count = count
        self.sessionIDStr = sessionIDStr
        self.singleTo = singleTo
        self.groupTo = groupTo
        self.projectGroupPathStr = projectGroupPathStr
        self.userIdentity = userIdentity
        self.isOnline = isOnline
        self.categoryID = categoryID
        self.categoryPhone = categoryPhone
        self.groupNameNote = groupNameNote
    }
}

// MARK: ChatSession convenience initializers and mutators

extension ChatSession {
    
    convenience init(data: Data) throws {
        let me = try newJSONDecoder().decode(ChatSession.self, from: data)
        self.init(id: me.id, sessionID: me.sessionID, type: me.type, groupType: me.groupType, labelText: me.labelText, image: me.image, name: me.name, top: me.top, notice: me.notice, from: me.from, to: me.to, unreadNum: me.unreadNum, lastModifyTime: me.lastModifyTime, updateTime: me.updateTime, lastMessageText: me.lastMessageText, disturb: me.disturb, delFlag: me.delFlag, show: me.show, lastMessageSeqID: me.lastMessageSeqID, lastMsgIncrement: me.lastMsgIncrement, isReadLastMessage: me.isReadLastMessage, orgID: me.orgID, projectID: me.projectID, reportFlag: me.reportFlag, groupNote: me.groupNote, count: me.count, sessionIDStr: me.sessionIDStr, singleTo: me.singleTo, groupTo: me.groupTo, projectGroupPathStr: me.projectGroupPathStr, userIdentity: me.userIdentity, isOnline: me.isOnline, categoryID: me.categoryID, categoryPhone: me.categoryPhone, groupNameNote: me.groupNameNote)
    }
    
    convenience init(_ json: String, using encoding: String.Encoding = .utf8) throws {
        guard let data = json.data(using: encoding) else {
            throw NSError(domain: "JSONDecoding", code: 0, userInfo: nil)
        }
        try self.init(data: data)
    }
    
    convenience init(fromURL url: URL) throws {
        try self.init(data: try Data(contentsOf: url))
    }
    
    func with(
        id: String? = nil,
        sessionID: String? = nil,
        type: Int? = nil,
        groupType: Int?? = nil,
        labelText: LabelText?? = nil,
        image: String? = nil,
        name: String? = nil,
        top: Bool? = nil,
        notice: String? = nil,
        from: String? = nil,
        to: String? = nil,
        unreadNum: Int? = nil,
        lastModifyTime: Int? = nil,
        updateTime: Int? = nil,
        lastMessageText: String? = nil,
        disturb: Int? = nil,
        delFlag: Bool? = nil,
        show: Bool? = nil,
        lastMessageSeqID: String?? = nil,
        lastMsgIncrement: String?? = nil,
        isReadLastMessage: Int? = nil,
        orgID: Int?? = nil,
        projectID: Int?? = nil,
        reportFlag: String? = nil,
        groupNote: String? = nil,
        count: JSONNull?? = nil,
        sessionIDStr: JSONNull?? = nil,
        singleTo: JSONNull?? = nil,
        groupTo: JSONNull?? = nil,
        projectGroupPathStr: JSONNull?? = nil,
        userIdentity: JSONNull?? = nil,
        isOnline: JSONNull?? = nil,
        categoryID: JSONNull?? = nil,
        categoryPhone: JSONNull?? = nil,
        groupNameNote: String? = nil
    ) -> ChatSession {
        return ChatSession(
            id: id ?? self.id,
            sessionID: sessionID ?? self.sessionID,
            type: type ?? self.type,
            groupType: groupType ?? self.groupType,
            labelText: labelText ?? self.labelText,
            image: image ?? self.image,
            name: name ?? self.name,
            top: top ?? self.top,
            notice: notice ?? self.notice,
            from: from ?? self.from,
            to: to ?? self.to,
            unreadNum: unreadNum ?? self.unreadNum,
            lastModifyTime: lastModifyTime ?? self.lastModifyTime,
            updateTime: updateTime ?? self.updateTime,
            lastMessageText: lastMessageText ?? self.lastMessageText,
            disturb: disturb ?? self.disturb,
            delFlag: delFlag ?? self.delFlag,
            show: show ?? self.show,
            lastMessageSeqID: lastMessageSeqID ?? self.lastMessageSeqID,
            lastMsgIncrement: lastMsgIncrement ?? self.lastMsgIncrement,
            isReadLastMessage: isReadLastMessage ?? self.isReadLastMessage,
            orgID: orgID ?? self.orgID,
            projectID: projectID ?? self.projectID,
            reportFlag: reportFlag ?? self.reportFlag,
            groupNote: groupNote ?? self.groupNote,
            count: count ?? self.count,
            sessionIDStr: sessionIDStr ?? self.sessionIDStr,
            singleTo: singleTo ?? self.singleTo,
            groupTo: groupTo ?? self.groupTo,
            projectGroupPathStr: projectGroupPathStr ?? self.projectGroupPathStr,
            userIdentity: userIdentity ?? self.userIdentity,
            isOnline: isOnline ?? self.isOnline,
            categoryID: categoryID ?? self.categoryID,
            categoryPhone: categoryPhone ?? self.categoryPhone,
            groupNameNote: groupNameNote ?? self.groupNameNote
        )
    }
    
    func jsonData() throws -> Data {
        return try newJSONEncoder().encode(self)
    }
    
    func jsonString(encoding: String.Encoding = .utf8) throws -> String? {
        return String(data: try self.jsonData(), encoding: encoding)
    }
}

enum LabelText: String, Codable {
    case empty = ""
    case 普通 = "普通"
    case 项目 = "项目"
}

// MARK: ChatSession 进行差异对比 来源于 DifferenceKit 主要进行基于差异的 列表的按需更新
extension ChatSession : Differentiable{
    var differenceIdentifier: String {
        return sessionID
    }
    
    func isContentEqual(to source: ChatSession) -> Bool {
        return name == source.name && from == source.from && to == source.to && unreadNum == source.unreadNum
    }
}


// MARK: ChatSession GRDB 的支持
// 定义数据库表结构
extension ChatSession : RDEntity {
    
    
    func didInsert(with rowID: Int64, for column: String?) {
        print("didInsert , rowID = \(rowID) , column = \(column)")
        self._id = rowID
    }
    
    func setRowId(_ rowID : Int64){
        self._id = rowID
    }
    
    
    func encode(to container: inout PersistenceContainer) {
        container["id"]                 = id
        container["sessionId"]          = sessionID
        container["type"]               = type
        container["image"]              = image
        container["name"]               = name
        container["top"]                = top
        container["from"]               = from
        container["to"]                 = to
        container["unreadNum"]          = unreadNum
        container["lastModifyTime"]     = lastModifyTime
        container["updateTime"]         = updateTime
        container["lastMessageText"]    = lastMessageText
        container["delFlag"]            = delFlag
        container["show"]               = show
        container["lastMessageSeqId"]   = lastMessageSeqID
        container["lastMsgIncrement"]   = lastMsgIncrement
        container["isReadLastMessage"]  = isReadLastMessage
        container["reportFlag"]         = reportFlag
    }
    
    static let databaseTableName = "table_session_bean"
    
    static let _id                  = DBColumn("_id")
    static let id                   = DBColumn("id")
    static let sessionID            = DBColumn("sessionId")
    static let type                 = DBColumn("type")
    static let image                = DBColumn("image")
    static let name                 = DBColumn("name")
    static let top                  = DBColumn("top")
    static let from                 = DBColumn("from")
    static let to                   = DBColumn("to")
    static let unreadNum            = DBColumn("unreadNum")
    static let lastModifyTime       = DBColumn("lastModifyTime")
    static let updateTime           = DBColumn("updateTime")
    static let lastMessageText      = DBColumn("lastMessageText")
    static let delFlag              = DBColumn("delFlag")
    static let show                 = DBColumn("show")
    static let lastMessageSeqID     = DBColumn("lastMessageSeqId")
    static let lastMsgIncrement     = DBColumn("lastMsgIncrement")
    static let isReadLastMessage    = DBColumn("isReadLastMessage")
    static let reportFlag           = DBColumn("reportFlag")
    
}
